
(function(){

    var Parser = function(_text){
    
        var text = _text;
        var pos = 0;
        var html_text = new String();
        
        var tag_flags = new Object();
        
        var list_indexes = new Array();
        var list_tags = new Array();
        
        var non_space_occured = false;
        
        var list_index = 0;
        var current_list_index = -1;
        
        var pageNames = getPageNames();
        
        var buffer = new String();
        
        var process = function(){
            for (; pos < text.length; pos++) {
                switch (text[pos]) {
                    case 'h':
                        if (pos + 6 < text.length &&
                        text[pos + 1] == 't' &&
                        text[pos + 2] == 't' &&
                        text[pos + 3] == 'p' &&
                        text[pos + 4] == ':' &&
                        text[pos + 5] == '/' &&
                        text[pos + 6] == '/') {
                            processLinkNatural();
                        }
                        else {
                        	buffer = buffer + text[pos];
                        }
                        break;
                    case '[':
                        processLink();
                        break;
                    case '=':
                        processHeading();
                        break;
                    case '#':
                        if (text.indexOf('#summary') == pos) {
                            processSummary();
                        }
                        else {
                            processList();
                        }
                        break;
                    case '_':
                        processItalic();
                        
                        break;
                    case '*':
                        if (list_index > 0 && !non_space_occured) {
                            processList();
                        }
                        else {
                            processBold();
                        }
                        
                        break;
                    case '^':
                        processSuper();
                        break;
                    case ',':
                        if (pos + 1 < text.length && text[pos + 1] == ',') {
                            processSub();
                        }
                        break;
                    case '~':
                        if (pos + 1 < text.length && text[pos + 1] == '~') {
                            processStrike();
                        }
                        break;
                    case '`':
                        processCode1();
                        break;
                    case '{':
                        if (pos + 2 < text.length && text[pos + 1] == '{' && text[pos + 2] == '{') {
                            processCode2();
                        }
                        break;
                    case '\n':
                        processNewLine();
                        break;
                    default:                    	
                        if (text[pos] != ' ') {
                            non_space_occured = true;                            
                        }
                        else {
                            list_index++;
                            pageNameCandidat = buffer.replace(/^\s+/, '');
                            // TODO link will not be recognized if it ends with a new line
                            if(pageNames[pageNameCandidat]) {                            	
                            	html_text = html_text + ' <a href="{{_path}}page/' + pageNameCandidat + '">' + pageNameCandidat + '</a>';
                            } else {
                            	html_text = html_text + buffer;
                            }
                            opera.postError('|' + buffer + '|');
                            buffer = '';                            
                        }
                    	buffer = buffer + text[pos];
                }
            }
        }
        
        var processLinkNatural = function(){
            var href = new String();
            for (; pos < text.length && text[pos] != ' ' && text[pos] != '\n' && text[pos] != '\t'; pos++) {
                href = href + text[pos];
            }
            buffer = buffer + '<a href="' + href + '">' + href + '</a>';
            
            if (text[pos] == '\n') {
                processNewLine();
            }
            else {
            	buffer = buffer + text[pos];
            }
        }
        
        var processLink = function(){
        	buffer = buffer + '<a href="';
            pos++;
            var href = new String();
            for (; pos < text.length && text[pos] != ']' && text[pos] != ' '; pos++) {
                href = href + text[pos];
            }
            
            // is it a link to wiki page?
            var firstPart;
            if(href.indexOf('#') >= 0) {
            	firstPart = href.split('#')[0];            	 
            }
            
            if (pageNames[href] || firstPart && pageNames[firstPart]) {
            	buffer = buffer + '{{_path}}page/';
            }
            
            buffer = buffer + href + '">';
            
            if (text[pos] == ']') {
            	buffer = buffer + href;
            }
            else {
                var desc = new String();
                for (; pos < text.length && text[pos] != ']'; pos++) {
                    desc = desc + text[pos];
                }
                if (desc.endsWith('.png') || desc.endsWith('.jpeg' || 
                			desc.endsWith('.jpg' || desc.endsWith('.gif')))) {
                	buffer = buffer + '<img src="' + desc + '">';
                }
                else {
                	buffer = buffer + desc;
                }
            }
            buffer = buffer + '</a>';
        }
        
        var processCode2 = function(){
        	buffer = buffer + '<code><pre>';
            for (pos = pos + 3; pos < text.length - 3; pos++) {
                if (text[pos] == '}' && text[pos + 1] == '}' && text[pos + 2] == '}') {
                    pos += 3;
                    break;
                }
                var symbol = text[pos];
                if (text[pos] == '<') {
                    symbol = '&lt;';
                }
                else 
                    if (text[pos] == '>') {
                        symbol = '&gt;';
                    }
                buffer = buffer + symbol;
                
            }
            buffer = buffer + '</pre></code>';
        }
        
        var processSummary = function(){
        	buffer = buffer + '<strong><i>';
            for (pos = pos + 'summary'.length + 1; pos < text.length; pos++) {
                if (text[pos] == '\n') {
                    break;
                }
                buffer = buffer + text[pos];
            }
            buffer = buffer + '</i></strong><br>';
        }
        
        var processCode1 = function(){
        	buffer = buffer + '<code>';
            for (pos = pos + 1; pos < text.length && text[pos] != '`'; pos++) {
                var symbol = text[pos];
                if (text[pos] == '<') {
                    symbol = '&lt;';
                }
                else 
                    if (text[pos] == '>') {
                        symbol = '&gt;';
                    }
                buffer = buffer + symbol;
            }
            buffer = buffer + '</code>';
        }
        
        var processList = function(){
            if (current_list_index == list_index) {
            	buffer = buffer + '<li>';
                
            }
            else 
                if (current_list_index < list_index) {
                    switch (text[pos]) {
                        case '#':
                        	buffer = buffer + '<ol><li>';
                            list_tags.push('</ol>');
                            break;
                        case '*':
                        	buffer = buffer + '<ul><li>';
                            list_tags.push('</ul>');
                            break;
                    }
                    current_list_index = list_index;
                    list_indexes.push(current_list_index);
                }
                // end of list
                else {
                	buffer = buffer + list_tags.pop();
                    current_list_index = list_indexes.pop();
                    if (list_tags.length > 0) {
                    	buffer = buffer + '<li>';
                    }
                }
            pos++;
            process();
        }
        
        var processHeading = function(){
            var n = 0;
            for (; pos < text.length && text[pos] == '='; pos++) {
                n++;
            }
            var heading = new String();
            for (; pos < text.length && text[pos] != '='; pos++) {
                heading = heading + text[pos];
            }
            buffer = buffer + '<h' + n + '>';
			
			var headlink = heading.replace(/\s/g, '_');
			buffer = buffer + '<a name="' + headlink + '"/>';
			
			buffer = buffer + heading + '</h' + n + '>';
            
            for (; pos < text.length && text[pos] == '='; pos++) {
            }
        }
        
        var processSuper = function(){
            if (!tag_flags.sup) {
            	buffer = buffer + '<sup>';
            }
            else {
            	buffer = buffer + '</sup>';
            }
            tag_flags.sup = !tag_flags.sup;
            pos++;
            process();
        }
        
        var processSub = function(){
            if (!tag_flags.sub) {
            	buffer = buffer + '<sub>';
            }
            else {
            	buffer = buffer + '</sub>';
            }
            tag_flags.sub = !tag_flags.sub;
            pos += 2;
            process();
        }
        
        var processStrike = function(){
            if (!tag_flags.strike) {
            	buffer = buffer + '<strike>';
            }
            else {
            	buffer = buffer + '</strike>';
            }
            tag_flags.strike = !tag_flags.strike;
            pos += 2;
            process();
        }
        
        var processItalic = function(){
            if (!tag_flags.italic) {
            	buffer = buffer + '<i>';
            }
            else {
            	buffer = buffer + '</i>';
            }
            tag_flags.italic = !tag_flags.italic;
            pos++;
            process();
        }
        
        var processBold = function(){
            if (!tag_flags.bold) {
            	buffer = buffer + '<b>';
            }
            else {
            	buffer = buffer + '</b>';
            }
            tag_flags.bold = !tag_flags.bold;
            pos++;
            process();
        }
        
        var processNewLine = function(){
            if (!non_space_occured && list_tags.length > 0) {
            	buffer = buffer + list_tags.pop();
                list_indexes.pop();
                current_list_index = -1;
            }
            buffer = buffer + '<br>';
            non_space_occured = false;
            list_index = 0;
            
            var dash_occured = false;
            var i = pos + 1;
            for (; i < text.length && text[i] != '\n'; i++) {
                if (text[i] != ' ' && text[i] != '-' && text[i] != '\t') {
                    break;
                }
                if (text[i] == '-') {
                    dash_occured = true;
                }
            }
            if (dash_occured) {
                pos = i - 1;
                buffer = buffer + '<hr>';
            }
        }
        
        this.parse = function(){
            process();
            return html_text;
        }
    }
    
    String.prototype.parseWiki = function(){
        var parser = new Parser(this);
        return parser.parse();
    }
    
    String.prototype.endsWith = function(portion){
        var line = this;
        var index = line.indexOf(portion);
        return line.length - index == portion.length;
    }
    
})();
